#include <QMessageBox>
#include <QWidget>
#include <QGroupBox>
#include <QApplication>
#include <QLineEdit>
#include <QPushButton>
#include <QComboBox>
#include <QTextEdit>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QRegularExpressionValidator>
#include "LargeNumCalcImpl.h"

class BigNumberCalculator : public QWidget {
    Q_OBJECT

public:
    explicit BigNumberCalculator(QWidget *parent = nullptr) : QWidget(parent) {
        // 增大字体
        setFont(QFont("微软雅黑", 12));
        // 设置窗口标题和大小，标题字号也要增大
        setWindowTitle("大数计算器");
        resize(800, 600);

        // 创建主布局
        QVBoxLayout *mainLayout = new QVBoxLayout(this);

        // 输入区，字号加大
        QGroupBox *inputGroupBox = new QGroupBox(QString::fromUtf8("输入大整数"));
        QVBoxLayout *inputLayout = new QVBoxLayout;

        msgBox = new QMessageBox(this);
        
        // 数1输入框
        input1 = new QLineEdit;
        // input1->setPlaceholderText("请输入第一个大数");
        // input1->setPlaceholderText方法中，需要放一个字符串变量，这个字符串会随着运算类型的改变而改变
        // 所以这里需要用一个QString变量来存储这个字符串
        QString input1PlaceholderText = QString::fromUtf8("请输入被加数");
        input1->setPlaceholderText(input1PlaceholderText);
        input1->setToolTip("支持粘贴");
        // input1支持输入数字，不能输入数字以外的字符，但是可以接受一个小数点，也可以不输入小数点
        input1->setValidator(new QRegularExpressionValidator(QRegularExpression("^\\d+(\\.\\d+)?$")));
        // 增加input1输入框的高度
        input1->setFixedHeight(40);
        // 当鼠标点击到input1时，如果原来焦点不在input1上，自动选中其中的所有文本
        // 事件过滤器安装
        input1->installEventFilter(this);
        inputLayout->addWidget(input1);

        // 数2输入框
        input2 = new QLineEdit;
        QString input2PlaceholderText = QString::fromUtf8("请输入加数");
        input2->setPlaceholderText(input2PlaceholderText);
        input2->setToolTip("支持粘贴");
        input2->setValidator(new QRegularExpressionValidator(QRegularExpression("^\\d+(\\.\\d+)?$")));
        // 增加input2输入框的高度
        input2->setFixedHeight(40);
        input2->installEventFilter(this);
        inputLayout->addWidget(input2);

        inputGroupBox->setLayout(inputLayout);
        mainLayout->addWidget(inputGroupBox);

        // 运算选择区
        QGroupBox *operationGroupBox = new QGroupBox("选择运算符");
        QHBoxLayout *operationLayout = new QHBoxLayout;

        // 运算类型下拉框
        operationComboBox = new QComboBox;
        operationComboBox->addItems({
            "加 (+)",
            "减 (-)",
            "乘 (×)",
            "除 (÷)",
            "次方 (a^b)",
            "阶乘 (a!)"
        });
        operationComboBox->setToolTip("选择运算类型");
        operationComboBox->setFixedHeight(40);
        operationLayout->addWidget(operationComboBox);
        // 当operationComboBox的当前索引改变时，触发如下callback
        connect(operationComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &BigNumberCalculator::onOperationComboBoxCurrentIndexChanged);

        // 运算按钮
        QPushButton *calculateBtn = new QPushButton("计算");
        calculateBtn->setToolTip("点击计算");
        calculateBtn->setFixedSize(80, 40);
        // 设置按钮字号
        calculateBtn->setFont(QFont("微软雅黑", 12));
        // 给按钮增加边框
        calculateBtn->setStyleSheet("QPushButton { "
            "border: 1px solid black;"
            "background-color: white;"
            "}");
        operationLayout->addWidget(calculateBtn);

        operationGroupBox->setLayout(operationLayout);
        mainLayout->addWidget(operationGroupBox);

        // 结果展示区
        QGroupBox *resultGroupBox = new QGroupBox("计算结果");
        QVBoxLayout *resultLayout = new QVBoxLayout;

        // 结果文本框
        result = new QTextEdit;
        result->setReadOnly(true);
        result->setPlaceholderText("计算结果将显示在这里");
        resultLayout->addWidget(result);

        resultGroupBox->setLayout(resultLayout);
        mainLayout->addWidget(resultGroupBox);

        // 历史记录区
        QGroupBox *historyGroupBox = new QGroupBox("历史记录");
        QVBoxLayout *historyLayout = new QVBoxLayout;

        // 历史记录文本框
        history = new QTextEdit;
        history->setReadOnly(true);
        history->setPlaceholderText("历史记录");
        historyLayout->addWidget(history);

        historyGroupBox->setLayout(historyLayout);
        mainLayout->addWidget(historyGroupBox);

        // 帮助按钮
        QHBoxLayout *helpLayout = new QHBoxLayout;
        QPushButton *helpBtn = new QPushButton("帮助");
        helpBtn->setToolTip("查看帮助");
        helpBtn->setFixedSize(60, 25);
        helpLayout->addStretch();
        helpLayout->addWidget(helpBtn);
        mainLayout->addLayout(helpLayout);

        // 设置布局
        setLayout(mainLayout);

        // 连接信号和槽
        connect(calculateBtn, &QPushButton::clicked, this, &BigNumberCalculator::onCalculateBtnClicked);
        connect(helpBtn, &QPushButton::clicked, this, &BigNumberCalculator::onHelpBtnClicked);

    }

    // 添加事件过滤函数
    bool eventFilter(QObject *obj, QEvent *event) {
        // 当鼠标点击到input1或input2时，如果原来焦点不在input1或input2上，自动选中其中的所有文本
        if (event->type() == QEvent::MouseButtonRelease) {
            if (obj == input1) {
                input1->selectAll();
            } else if (obj == input2) {
                input2->selectAll();
            }
        }
        return QWidget::eventFilter(obj, event);
    }

private slots:
    void onCalculateBtnClicked() {
        result->clear();
        // 从input1和input2中获取输入的字符串
        string num1 = input1->text().toStdString();
        string num2 = input2->text().toStdString();
        // 从operationComboBox中获取当前索引
        int index = operationComboBox->currentIndex();
        // 根据当前索引，调用不同的函数
        switch (index) {
        case 0:
            result->setText(QString::fromStdString(LargeNumCalcImpl::add(num1, num2)));
            break;
        case 1:
            result->setText(QString::fromStdString(LargeNumCalcImpl::subtract(num1, num2)));
            break;
        case 2:
            result->setText(QString::fromStdString(LargeNumCalcImpl::multiply(num1, num2)));
            break;
        case 3:
            result->setText(QString::fromStdString(LargeNumCalcImpl::divide(num1, num2)));
            break;
        case 4:
            result->setText(QString::fromStdString(LargeNumCalcImpl::power(num1, num2)));
            break;
        case 5:
            result->setText(QString::fromStdString(LargeNumCalcImpl::factorial(num1)));
            break;
        default:
            break;
        }
        // 新建一个字符串数组，依次是：" + "," - "," × "," ÷ ","^","!"
        string operations[] = {" + "," - "," × "," ÷ ","^","!"};
        // 从operationComboBox中获取当前索引
        int idx = operationComboBox->currentIndex();
        // 从operations数组中获取当前运算符
        string operation = operations[idx];
        // 记录历史记录，末尾加一个换行
        string historyRecord = num1 + operation + num2 + " = " + result->toPlainText().toStdString() + "\n";
        history->append(QString::fromStdString(historyRecord));
    }

    void onHelpBtnClicked() {
        msgBox->setText("操作说明：\n"
                            "1. 输入两个大数\n"
                            "2. 选择运算类型\n"
                            "3. 点击“计算”按钮\n"
                            "4. 结果将显示在下方");
        msgBox->exec();
    }

    // 当operationComboBox的当前索引改变时，触发如下callback
    void onOperationComboBoxCurrentIndexChanged(int index) {
        input2->setEnabled(true);
        input1->setValidator(new QRegularExpressionValidator(QRegularExpression("^\\d+(\\.\\d+)?$")));
        input2->setValidator(new QRegularExpressionValidator(QRegularExpression("^\\d+(\\.\\d+)?$")));
        // 根据当前索引，更新input1和input2的占位符文本
        switch (index) {
        case 0:
            input1->setPlaceholderText("请输入被加数");
            input2->setPlaceholderText("请输入加数");
            break;
        case 1:
            input1->setPlaceholderText("请输入被减数");
            input2->setPlaceholderText("请输入减数");
            break;
        case 2:
            input1->setPlaceholderText("请输入被乘数");
            input2->setPlaceholderText("请输入乘数");
            break;
        case 3:
            input1->setPlaceholderText("请输入被除数");
            input2->setPlaceholderText("请输入除数");
            break;
        case 4:
            input1->setPlaceholderText("请输入底数");
            input2->setPlaceholderText("请输入指数");
            input2->clear();
            // input1和input2改成只支持数字，不包括小数点
            input1->setValidator(new QRegularExpressionValidator(QRegularExpression("^\\d+$")));
            input2->setValidator(new QRegularExpressionValidator(QRegularExpression("^\\d+$")));
            break;
        case 5:
            input1->setPlaceholderText("请输入阶乘数");
            input2->setPlaceholderText("");
            input1->setValidator(new QRegularExpressionValidator(QRegularExpression("^\\d+$")));
            input1->clear();
            input2->clear();
            // input2变成不可用
            input2->setEnabled(false);
            break;
        default:
            break;
        }
    }

private:
    QLineEdit *input1;
    QLineEdit *input2;
    QComboBox *operationComboBox;
    QTextEdit *result;
    QTextEdit *history;
    QMessageBox *msgBox;
    LargeNumCalcImpl calc;
};

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    BigNumberCalculator calculator;
    calculator.show();
    return app.exec();
}

#include "BigNumberCalculator.mop"